为了账号安全,请及时绑定邮箱和手机立即绑定

给Bootstrap-table插件添加tree功能

标签:
JQuery Bootstrap
一、最终效果图

工作中想用如图的方式去展示数据,虽然网上也有其它人写的相关插件,但是几乎都是一次性请求好数据并且不支持分页,不符合项目需求,所以就自己改了个,尽量避免动原插件的既有功能,当点击行前的折叠图标时,会通过ajax从后台调取数据并插入到表格中。
table-tree

二、相关代码

1、修改 BootstrapTable.prototype.initHeader 函数

 /* 2018.01.10 为树域td添加class start */
    var tempClass='';
    if(that.options.treeView && column['field']===that.options.treeField){
        tempClass=column['class']+' tree-field ';
    }else{
        tempClass=column['class'];
    }
    var text = '',
        halign = '', // header align style
        align = '', // body align style
        style = '',
        class_ = sprintf(' class="%s"', tempClass),
        order = that.options.sortOrder || column.order,
        unitWidth = 'px',
        width = column.width;
/* 2018.01.10 为树域td添加class end */

2、修改 BootstrapTable.prototype.initRow 函数

/* 2018.01.10 表格树DOM结构 start */
    var content=value;
    if (that.options.treeView && column.field == that.options.treeField) {
        var tempIsLastChild=$.extend(true,[],item.isLastChild);
        var indent='',indentCount=0,treeRootLevel,treeMaxLevel,
            selfIsLastChild=(tempIsLastChild.pop())?' tree-branch-last':'',
            iconStatus=item.isExpand?' tree-expand':' tree-collapse';
        // 对参数配置进行校验
        if (that.options.treeRootLevel===undefined) {
            treeRootLevel=data[0][that.options.treeLevelField]||0;
            $.each(data,function(_index,v){
                v[that.options.parentId]=v[that.options.parentId]||'';
                treeRootLevel=Math.min(treeRootLevel,v[that.options.treeLevelField]);
            });
        }else{
            treeRootLevel=parseInt(that.options.treeRootLevel);
        }
        // 防止 treeRootLevel 为非数字的情况
        treeRootLevel=treeRootLevel||0;
        treeMaxLevel=that.options.treeMaxLevel||Infinity;
        item[that.options.treeParentLevelField]=item[that.options.treeParentLevelField]||treeRootLevel;
        // 结构树的html
        indent='<div class="tree-indent">';
        if(item[that.options.parentId]||that.options.treeRootLevel!==undefined){// 绘制数据前的树结构线
            for(var _index=treeRootLevel;_index<=item[that.options.treeParentLevelField];_index++){
                indentCount++;
                if (tempIsLastChild.shift()) {
                    indent+='<div class="tree-branch-101 tree-branch-last-child"></div>';
                }else{
                    indent+='<div class="tree-branch-101"></div>';
                }
            }
        }
        if(item[that.options.treeLevelField]<treeMaxLevel){// 当前td数据是否还有下级
            indentCount++;
            indent+='<div class="tree-icon-wrapper tree-icon-branch-100 tree-icon-branch-001'+selfIsLastChild+'">'
                    +'<span class="tree-icon-branch-010 tree-icon treefont'+iconStatus+'"></span>'
                    +'</div>';
        }else{
            indentCount++;
            indent+='<div class="tree-icon-wrapper tree-branch-101 tree-branch-010'+selfIsLastChild+'"></div>';
        }
        indent+='</div>';
        // 表格数据及缩进
        content='<div class="tree-content text-left" style="padding-left:'+(32*indentCount)+'px">'+value+'</div>';
    }
    text = that.options.cardView ? ['<div class="card-view">',
        that.options.showHeader ? sprintf('<span class="title" %s>%s</span>', style,
            getPropertyFromOther(that.columns, 'field', 'title', field)) : '',
        sprintf('<span class="value">%s</span>', value),
        '</div>'
    ].join('') : [sprintf('<td%s %s %s %s %s %s %s>',
            id_, class_, style, data_, rowspan_, colspan_, title_),
        indent,
        content,
        '</td>'
    ].join('');
/* 2018.01.10 表格树DOM结构 end */

3、修改 BootstrapTable.prototype.initBody 函数

// 在函数头部的循环中为每个节点增加isLastChild属性
for (var i = this.pageFrom - 1; i < this.pageTo; i++) {
    var item = data[i];
    /* 2018.01.11 设置节点是否是最后一个 start */
    if (that.options.treeView && data.length>0) {
        if (!item.isLastChild) {
            item.isLastChild=[];
            if (i==this.pageTo-1) {
                item.isLastChild.push(true);
            }else{
                item.isLastChild.push(false);
            }
        }
    }
    /* 2018.01.11 设置节点是否是最后一个 end */
    var tr = this.initRow(item, i, data, trFragments);
    hasTr = hasTr || !!tr;
    if (tr&&tr!==true) {
        trFragments.append(tr);
    }
}

/* 2018.01.10 展开和折叠表格树事件绑定 start */
    this.$body.find('> tr[data-index] > td .tree-icon').off('click').on('click', function (e) {
        e.stopPropagation();
        var $this = $(this),
            $tr = $this.closest('tr'),
            index = $tr.data('index'),
            row = data[index];
        var icon = $(this);
        // 给被点击的行数据添加一个isExpand字段,记录它的“展开/折叠”状态
        row.isExpand=!row.isExpand;
        // 处理展开和折叠事件
        if (icon.hasClass('tree-expand')) {
            // 梳理需要折叠的tr行号范围,parentId为父节点的Id
            var start=index;
            if (row.isLastChild[row.isLastChild.length-1]) {
                for (var i = index+1; i <data.length; i++) {
                    if (row[that.options.treeId] == data[i][that.options.parentId]) {
                        start=i;
                    }
                }
                if (data[start].isExpand) {
                    that.$body.find('> tr:eq('+start+') .tree-icon').click();
                }
            }else{
                for (var i = index+1; i <data.length; i++) {
                    if (row[that.options.parentId] == data[i][that.options.parentId]) {
                        start=i-1;
                        break;
                    }
                }
            }
            // 删除被折叠掉的tr行
            for (var i = start; i >index; i--) {
                data.splice(i,1);
            }
        } else {
            // 展开子节点时,首先通过 getChild 函数获取子节点(这里假设是同步ajax请求,想要异步可适当调整)
            var child=that.options.getChild(index, that.options.treeId);
            if (child.length>0) {
                child[0].isLastChild=true;
            }
            // 将子节点循环插入到当前节点后面
            $.each(child, function (i, v) {
                // 设置该行tree-field中的所有辅助线是否是同级最后一个,以便区别样式
                v.isLastChild=$.extend(true,[],row.isLastChild);
                if (i===0) {
                    v.isLastChild.push(true);
                }else{
                    v.isLastChild.push(false);
                }
                if (row[that.options.treeId] == v[that.options.parentId]) {
                    data.splice(index+1,0,v);
                }
            });
        }
        // 重绘页面表格
        that.initBody(true);
    });
/* 2018.01.10 展开和折叠表格树事件绑定 end */

4、iconfont及css样式

增加了少许样式和字体,较简单,详见代码。

三、后记

1、目前 getChild 函数获取数据时,还只支持同步请求,后续将改为支持异步;

2、代码及DEMO

点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
37
获赞与收藏
70

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消